package de.joergviola.mobj.client.database;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.google.code.gwt.database.client.GenericRow;
import com.google.code.gwt.database.client.SQLError;
import com.google.code.gwt.database.client.SQLResultSet;
import com.google.code.gwt.database.client.SQLResultSetRowList;
import com.google.code.gwt.database.client.SQLTransaction;
import com.google.code.gwt.database.client.StatementCallback;
import com.google.gwt.user.client.rpc.AsyncCallback;

import de.joergviola.mobj.shared.Entity;
import de.joergviola.mobj.shared.Schema;

public class Select<T extends Serializable> {

	private static final Logger log = Logger.getLogger("Select");
	private final Entity<T> entity;
	private String sql;
	private Object[] args;
	protected Schema schema;

	public Select(Schema schema, Entity<T> entity, String where) {
		this.schema = schema;
		this.entity = entity;
		this.sql = "SELECT * FROM " + entity.getEntityName();
		if (where != null && where.length() > 0) {
			this.sql += " WHERE " + where;
		}
	}

	public void execute(SQLTransaction tx, final AsyncCallback<List<T>> callback) {
		log.info(sql + " : " + Arrays.toString(args));
		tx.executeSql(getSQL(), getArgs(), new StatementCallback<GenericRow>() {

			@Override
			public void onSuccess(SQLTransaction transaction,
					SQLResultSet<GenericRow> resultSet) {
				ArrayList<T> result = new ArrayList<T>();
				SQLResultSetRowList<GenericRow> rows = resultSet.getRows();
				if (rows.getLength() == 0) {
					callback.onSuccess(result);
					return;
				}
				Barrier<List<T>> barrier = new Barrier<List<T>>(callback,
						result);
				for (GenericRow row : rows) {
					DBEntityReader reader = new DBEntityReader(schema,
							transaction, barrier, row);
					try {
						barrier.enter();
						T t = entity.getObject(reader);
						result.add(t);
						barrier.onSuccess();
					} catch (Throwable caught) {
						barrier.onFailure(caught);
						return;
					}
				}
				// callback.onSuccess(result);
			}

			@Override
			public boolean onFailure(SQLTransaction transaction, SQLError error) {
				log.log(Level.SEVERE, error.getMessage());
				return true;
			}
		});
	}

	private String getSQL() {
		return sql;
	}

	public Object[] getArgs() {
		return args;
	}

	public void setArgs(Object[] args) {
		this.args = args;
	}

}
